package com.easy.app.controller.monitor;

import com.easy.framework.cache.RedisCache;
import com.easy.framework.common.constant.Constants;
import com.easy.framework.common.model.R;
import com.easy.framework.common.utils.Func;
import com.easy.framework.database.page.PageUtil;
import com.easy.framework.database.page.Pagination;
import com.easy.framework.security.model.LoginUser;
import com.easy.framework.security.service.RedisOAuth2AuthorizationService;
import com.easy.framework.security.utils.SecurityUtils;
import com.easy.framework.web.base.BaseController;
import com.easy.module.log.annotation.Log;
import com.easy.module.log.enums.Operation;
import com.easy.module.system.model.UserOnlineModel;
import com.easy.module.system.query.UserOnlineQuery;
import com.easy.module.system.service.ISysUserOnlineService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 在线用户监控
 *
 * @author Easy
 */
@RequiredArgsConstructor
@RestController
@RequestMapping("/monitor/online")
public class SysUserOnlineController extends BaseController {

    private final ISysUserOnlineService userOnlineService;

    private final RedisCache redisCache;

    private final RedisOAuth2AuthorizationService redisOAuth2AuthorizationService;

    @PreAuthorize("@perm.hasPermission('system:online$list')")
    @GetMapping("/list")
    public R<Pagination<UserOnlineModel>> list(UserOnlineQuery query) {
        Collection<String> keys = redisCache.keys(Constants.ACCESS_TOKEN_KEY + "*");
        List<UserOnlineModel> userOnlineList = new ArrayList<UserOnlineModel>();
        for (String key : keys) {
            String token = key.replace(Constants.ACCESS_TOKEN_KEY, "");
            LoginUser user = SecurityUtils.getUser(token);
            UserOnlineModel userOnlineModel = null;
            if (Func.isNotEmpty(query.getIp()) && Func.isNotEmpty(query.getUsername())) {
                userOnlineModel = userOnlineService.selectOnlineByInfo(query.getIp(), query.getUsername(), user);
            } else if (Func.isNotEmpty(query.getIp())) {
                userOnlineModel = userOnlineService.selectOnlineByIpaddr(query.getIp(), user);
            } else if (Func.isNotEmpty(query.getUsername())) {
                userOnlineModel = userOnlineService.selectOnlineByUsername(query.getUsername(), user);
            } else {
                userOnlineModel = userOnlineService.loginUserToUserOnline(user);
            }
            userOnlineModel.setAccessToken(token);
            userOnlineList.add(userOnlineModel);
        }
        Collections.reverse(userOnlineList);
        Collections.sort(userOnlineList, (o1, o2) -> o2.getLoginAt().compareTo(o1.getLoginAt()));
        userOnlineList.removeAll(Collections.singleton(null));
        return R.success(PageUtil.page(query.getPageNum(), query.getPageSize(), userOnlineList));
    }

    /**
     * 强退用户
     */
    @PreAuthorize("@perm.hasPermission('system:online$forceLogout')")
    @Log(title = "在线用户", type = Operation.KICKED)
    @DeleteMapping("/{token}")
    public R forceLogout(@PathVariable("token") String token) {
        OAuth2Authorization oAuth2Authorization = redisOAuth2AuthorizationService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
        redisOAuth2AuthorizationService.remove(oAuth2Authorization);
        return R.success();
    }
}
